﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Checkpoint2XNA.Models
{
    public class Box: Model3D
    {
        public Vector3 MinCorner { get; set; }
        public Vector3 MaxCorner { get; set; }

        public Box(Vector3 p, float w, float l, float h, Color c)
        {
            MinCorner = new Vector3(p.X - w/2, p.Y, p.Z - l/2);
            MaxCorner = new Vector3(p.X + w/2, p.Y + h, p.Z + l/2);
            Color = c;
        }

        public override void MoveTo(Vector3 p)
        {
            var sizes = MaxCorner - MinCorner;
            MinCorner = new Vector3(p.X - sizes.X / 2, p.Y, p.Z - sizes.Z / 2);
            MaxCorner = new Vector3(p.X + sizes.X / 2, p.Y +sizes.Y, p.Z + sizes.Z / 2);
        }

        public override Microsoft.Xna.Framework.Color GetColorAt(Vector3 point)
        {
            return Color;
        }

        public override Microsoft.Xna.Framework.Vector3 GetNormal(Vector3 point)
        {
            //forget the bottom, no one will see it
            if (point.X <= MinCorner.X + 1E-6) return new Vector3(-1, 0, 0);
            else if (point.Z <= MinCorner.Z + 1E-6) return new Vector3(0, 0, -1);
            else if (point.X >= MaxCorner.X - 1E-6) return new Vector3(1, 0, 0);
            else if (point.Y >= MaxCorner.Y - 1E-6) return new Vector3(0, 1, 0);
            else return new Vector3(0, 0, 1);
        }

        public double BetterRayCollide(Vector3 origin, Vector3 ray, Vector3 inverseRay)
        {

            Vector3 tvmin = (MinCorner - origin) * inverseRay;
            Vector3 tvmax = (MaxCorner - origin) * inverseRay;

            float temp;
            if (tvmin.X > tvmax.X)
            {
                temp = tvmax.X;
                tvmax.X = tvmin.X;
                tvmin.X = temp;
            }
            if (tvmin.Y > tvmax.Y)
            {
                temp = tvmax.Y;
                tvmax.Y = tvmin.Y;
                tvmin.Y = temp;
            }
            if (tvmin.Z > tvmax.Z)
            {
                temp = tvmax.Z;
                tvmax.Z = tvmin.Z;
                tvmin.Z = temp;
            }


            //double tmin = Max(tvmin.X, tvmin.Y, tvmin.Z);
            //double tmax = Min(tvmax.X, tvmax.Y, tvmax.Z); 
            double tmin = tvmin.X > tvmin.Y ? (tvmin.X > tvmin.Z ? tvmin.X : tvmin.Z) : (tvmin.Y > tvmin.Z ? tvmin.Y : tvmin.Z);
            double tmax = tvmax.X < tvmax.Y ? (tvmax.X < tvmax.Z ? tvmax.X : tvmax.Z) : (tvmax.Y < tvmax.Z ? tvmax.Y : tvmax.Z);

            // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
            if (tmax < 0)
            {
                return -1;
            }

            // if tmin > tmax, ray doesn't intersect AABB
            if (tmin > tmax)
            {
                return -1;
            }

            return tmin;
        }

        public override double RayCollide(Vector3 origin, Vector3 ray)
        {
            Vector3 dirfrac = new Vector3();
            dirfrac.X = 1.0f / ray.X;
            dirfrac.Y = 1.0f / ray.Y;
            dirfrac.Z = 1.0f / ray.Z;

            return BetterRayCollide(origin, ray, dirfrac);
        }
    }
}
